# app.py
# provide entry point for use_pymupdf
from base64 import b64encode
from tempfile import mkstemp

from flask import *
from werkzeug.utils import secure_filename

from tikz_pdfdumper import *

API_PATH = "/__py_api"
UPLOAD_FOLDER = "/home/na/git/hb3/resources"
ALLOWED_FILE_EXTENSIONS = ("pdf",)
SECRET_KEY = "s0me_random_s3cret_key"

def allowed_file(filename: str, ext = tuple()) -> bool:
    return "." in filename and filename.split(".")[-1].lower() in ALLOWED_FILE_EXTENSIONS + ext

app = Flask(__name__)
app.secret_key = SECRET_KEY
app.config["SESSION_TYPE"] = "filesystem"


@app.route(f"{API_PATH}/upload_pdf", methods=["GET", "POST"])
def upload_pdf():  # https://flask.palletsprojects.com/en/2.2.x/quickstart/#file-uploads
    """
    return:
    {
        "text": pdf text content, no ocr content
        "images": [ List of images
            "image": b64-encoded raw image,
            "boxes": character boxes, coordinate start from upleft
        ]
    }
    """


    if request.method == "POST":
        # handle 405
        if "file" not in request.files:
            flash("No valid pdf")
            return redirect(request.url)
        f = request.files["file"]
        if f.filename == "":
            flash("No selected file")
            return redirect(request.url)
        if not allowed_file(f.filename):
            flash("file extension is not safe")
            return redirect(request.url)
        # save uploaded pdf
        # fp, filename = mkstemp(secure_filename(f.filename), "", UPLOAD_FOLDER)
        # f.save(fp)
        text, images = pdftotext(f.stream.read())
        return {
            "text": text,
            "images": [  # remove image, only locate string using coordination. (04-12)
                [{"image": "base64:"+b64encode(bytes(x[0])).decode(), "boxes": x[2]} for x in images]
            ]
        }
    #
    return """
    <!doctype html>
    <title>Upload a new pdf</title>
    <form method=post enctype=multipart/form-data>
        <input type=file name=file>
        </br>
        <input type=submit value=Upload>
    </form>
    """

@app.route(f"{API_PATH}/box_image", methods=["POST"])  # POST 以外的请求会返回 405
def draw():
    """
    return:
    path_to_new_pdf: str

    必选参数：    
    pdf_path: path to pdf
    highlight: [
        {
            xref: int,
            rects: [
                {
                    x, y, w, h
                }
            ]
        }
    ]
    如果该路径不是 py 的子路径，则返回 EACCES
    文件找不到返回 ENOENT
    少一个返回 EINVAL

    可选参数：
    color: RGBA 十六进制编码的字符串
    如果没有 A 则 A 为 7f
    如果没有 color 则为 ffff007f
    """
    from os.path import abspath
    from PIL import ImageDraw
    (EINVAL := "Error: Invalid argument", EACCESS := "Error: Permission denied")
    ARG_LIST = ("pdf_path", "coord",)  # arg that must provides
    OPT_ARG_LIST = ("color",)
    ARGS = {}
    try:
        ffbt = None
        if request.method == "POST":
            if "json" in request.content_type:
                ffbt = request.json

        for i in ARG_LIST:
            ARGS[i] = ffbt[i]
        ARGS["highlight"] = ffbt["coord"]["highlight"]
        if "color" in ffbt["coord"]: ARGS["color"] = ffbt["coord"]["color"]
        ARGS.pop("coord")
        for i in OPT_ARG_LIST:
            if i in ffbt: ARGS[i] = ffbt[i]
        if abspath(UPLOAD_FOLDER) not in abspath(ARGS["pdf_path"]): return EACCESS  # TODO: 只允许和 py 同一层
        if not allowed_file(ARGS["pdf_path"]): return EINVAL + "File is Dangerous",410  # 文件名必须以 .pdf 结尾
        from colorimage_andeditpdf import colorimage
        return colorimage(**ARGS)
    except AttributeError:
        return EINVAL, 410
    except ValueError:  # float()
        return EINVAL, 410
    except Exception:
        return "Failed", 500
    
@app.route(f"{API_PATH}/down_pdf/<name>")
def download(name):
    """
    :param name: filename
    :return: 404 if not found
    """
    return send_from_directory(UPLOAD_FOLDER, name)


@app.route("/")
def hello_world():
    return """
    <h1> Welcome to Nginx! </h1>
    """


# if using apache httpd as backend server, consider using mod_wsgi as server
if __name__ == "__main__":
    app.run(port=5010)
